<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>简易CE工具</title>
	<link href="https://cdn.bootcss.com/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
	<script src="http://eejs.yinsin.net/eejs-api.min.js"></script>
	<script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
	
	<style>
	html, body {width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;background: #f0f0f0;}
	.list-box {width: 100%; height: calc(100% - 90px); float: left;}
	.line{ line-height: 32px; width: 100%; margin: 5px; float: left;}
	#processPath{ width: 400px;}
	.box-left {width: 400px; height: 450px;overflow: auto; float: left;}
	.box-right {width: 300px; float: right;}
	.table {width: 100%; background: #dddddd;}
	.table td {background: #ffffff;}
	.cover {width: 100%; height: 100%; position: absolute; left: 0; top: 0; text-align: center; background-color: #555555; opacity: 0.5; z-index: 2;}
	.cover img {margin-top: 200px;}
	.hidden {display: none;}
	.trline {cursor: pointer;}
	.trline:hover td {background: #f4f2bf; color: #ff0000;}	
	</style>
</head>

<body>
	<div class="cover hidden">
		<img src="240.gif" width="128" height="128"/>
	</div>
	<div class="line">
		<select class="form-control" id="processList">
			<option value="">---选择进程---</option>
		</select>
		<button id="btn-flush" class="btn">刷新</button>
		<input type="text" class="form-control" id="processPath" readonly/>
	</div>
	<div class="line">
		<div class="box-left">
			<div class="tips">未搜索</div><label><input type="checkbox" id="monitor" disabled/> 监听值变化</label>
			<table class="table" cellpadding="0" cellspacing="1" border="0">
				<thead>
					<tr>
						<th>序号</th>
						<th>内存地址</th>
						<th>当前值</th>
						<th>先前值</th>
					</tr>
				</thead>
				<tbody id="data-body">
				
				</tbody>
			</table>
		</div>
		<div class="box-right">
			<div class="line">
				<button id="btn-first" class="btn btn-success" data-flag="0">首次扫描</button>
				<button id="btn-again" class="btn" data-flag="0" disabled>再次扫描</button>
				<button id="btn-back" class="btn" disabled>撤销扫描</button>
			</div>
			<div class="line">
				<label for="datatype">数据类型：</label>
				<select class="form-control" id="datatype">
					<option value="5">字节型</option>
					<option value="1" selected>4字节(整数型)</option>
					<option value="2">字符串</option>
					<option value="3">浮点型</option>
					<option value="4">双浮点型</option>
				</select>
				<label for="input">搜索内容：</label>
				<input type="text" class="form-control" id="input"/>				
			</div>
			<div class="line">
				<label for="stype">扫描类型：</label>
				<select class="form-control" id="stype" disabled>
					<option value="0" selected>精确查找</option>
					<option value="-1">不变的数值</option>
					<option value="-2">变大的数值</option>
					<option value="-3">变小的数值</option>
					<option value="-4">改变的数值</option>
				</select>
			</div>
			<div class="line">
				<label for="update">修改内存：</label>
				<input type="text" class="form-control" id="address" placeholder="内存地址（十六进制）"/>
				<input type="text" class="form-control" id="update" placeholder="数据"/>
				<button id="btn-update" class="btn">修改</button>
			</div>
		</div>
	</div>

	<script type="text/javascript">		
		ee.AppConfig({
			"title": "简易CE工具",
			"width": 720, 
			"height": 540, 
			"debug": false,
			"max": false,
			"min": true,
			"close": true,
			"resize": false,
			"border": true
		});
		
		var pdata = [];
		var mdata = [];
		var processId = -1;
		window.onload = function(){
			setTimeout(function(){
				ee.processAdjustPrivate({"private": 20, "enable": true}, function(){
					loadProcessList();
				});
			}, 200);
			
			$('#processList').on('change', function(){
				var pid = $('#processList').val();
				if(processId != pid){
					processId = pid;
					loadProcessPath($('#processList').val());
				}				
			});

			$('#btn-first').on('click', function(){				
				var that = $('#btn-first');
				var flag = that.data('flag');
				if(flag == '0'){
					if(!processId){
						alert('请选择进程');
						return;
					}
					that.data('flag', '1');
					$('#input').attr("readonly", true);
					$('#stype').attr("disabled", false);
					$('#processList').attr("disabled", true);
					$('.cover').removeClass('hidden');
					setTimeout(function(){
						firstSearch(processId, $('#input').val());
					}, 100);
				} else {
					that.data('flag', '0');
					that.text('首次搜索');
					$('#data-body').html('');
					$('#btn-again').attr("disabled", true).removeClass('btn-primary');
					$('#btn-back').attr("disabled", true).removeClass('btn-warning');
					$('#input').attr("readonly", false);
					$('#stype').val('0').attr("disabled", true);
					$('#processList').attr("disabled", false);
				}
			});

			$('#btn-again').on('click', function(){
				var flag = $('#btn-first').data('flag');
				if(flag != '0'){					
					$('.cover').removeClass('hidden');
					setTimeout(function(){
						againSearch($('#stype').val());
					}, 100);
				}
			});

			$('#btn-back').on('click', function(){
				var flag = $('#btn-again').data('flag');
				if(flag != '0'){					
					$('.cover').removeClass('hidden');
					$('#btn-back').attr("disabled", true).removeClass('btn-warning');
					setTimeout(function(){
						backSearch($('#stype').val());
					}, 100);
				}
			});

			$('#btn-flush').on('click', function(){
				loadProcessList();
			});

			$('#btn-update').on('click', function(){
				updateData();
			});

			$('.table').on('click', '.trline', function(){
				var $tr = $(this);
				var num = $tr.data('index');
				var i = parseInt(num) - 1;
				$('#address').val(int2hex(mdata[i].address));
				$('#update').val(mdata[i].value);
			});

			setInterval(function(){
				if($('#monitor').is(':checked')){
					monitorAddress();
				}
			}, 2000);
		};

		function monitorAddress(){
			var datatype = $('#datatype').val();
			var updates = function(i, v, d){
				if(v != mdata[i].value){
					mdata[i].old = mdata[i].value;
					mdata[i].value = v;
					$('#TR' + int2hex(d) + ' .vv').text(mdata[i].value);
					$('#TR' + int2hex(d) + ' .oo').text(mdata[i].old);
				}
			};
			for(var i = 0; i < mdata.length; i++){
				var address = mdata[i].address;
				if(datatype == 1){ // 整数型
					ee.processReadInt({"pid": processId, "address": address}, function(ret){
						updates(i, ret.value, address);					
					});
				} else if(datatype == 2){ // 文本型
					ee.processReadString({"pid": processId, "address": address}, function(ret){
						updates(i, ret.value, address);
					});
				} else if(datatype == 3){ // 浮点型
					ee.processReadFloat({"pid": processId, "address": address}, function(ret){
						updates(i, ret.value, address);
					});
				} else if(datatype == 4){ // 双浮点型
					ee.processReadDouble({"pid": processId, "address": address}, function(ret){
						updates(i, ret.value, address);
					});
				} else if(datatype == 5){ // 字节型
					ee.processReadBit({"pid": processId, "address": address}, function(ret){
						updates(i, ret.value, address);
					});
				}
			}
		}

		function firstSearch(pid, v){
			ee.processMemorySearch({'pid': pid, 'datatype': $('#datatype').val(), 'data': v}, function(ret){
				mdata = [];
				if(ret.count < 20){
					$('#monitor').attr('disabled', false);
				} else {
					$('#monitor').attr('checked', false).attr('disabled', true);
				}
				if(ret.count > 0){
					mdata = ret.list;
					$('.tips').html('搜索到'+ret.count+'个结果' + (ret.count > 500 ? '，因结果过多，暂不显示': ''));
					if(ret.list && ret.list.length){
						mdata = ret.list;
						renderTable(ret.list);
					}
				} else {
					$('#data-body').html('');
					$('.tips').html('未搜索到结果');
				}
				$('.cover').addClass('hidden');
				$('#btn-again').attr("disabled", false).addClass('btn-primary');
				$('#btn-first').text('新的搜索');
			});
		}

		function againSearch(stype){
			ee.processMemorySearchAgain({"stype": stype}, function(ret){
				mdata = [];
				if(ret.count < 20){
					$('#monitor').attr('disabled', false);
				} else {
					$('#monitor').attr('checked', false).attr('disabled', true);
				}
				if(ret.count > 0){
					mdata = ret.list;
					$('.tips').html('搜索到'+ret.count+'个结果' + (ret.count > 500 ? '，因结果过多，暂不显示': ''));
					if(ret.list && ret.list.length){
						mdata = ret.list;
						renderTable(ret.list);
					}
				} else {
					$('#data-body').html('');
					$('.tips').html('未搜索到结果');
				}				
				$('#btn-again').data('flag', '1');
				$('#btn-back').attr("disabled", false).addClass('btn-warning');
				$('.cover').addClass('hidden');
			});
		}

		function backSearch(){
			ee.processMemorySearchRevoke({}, function(ret){
				mdata = [];
				if(ret.count < 20){
					$('#monitor').attr('disabled', false);
				} else {
					$('#monitor').attr('checked', false).attr('disabled', true);
				}
				if(ret.count > 0){
					mdata = ret.list;
					$('.tips').html('搜索到'+ret.count+'个结果' + (ret.count > 500 ? '，因结果过多，暂不显示': ''));
					if(ret.list && ret.list.length){
						mdata = ret.list;
						renderTable(ret.list);
					}
				} else {
					$('#data-body').html('');
					$('.tips').html('未搜索到结果');
				}
				$('#btn-again').data('flag', '0');
				$('.cover').addClass('hidden');
			});
		}

		function updateData(){
			var datatype = $('#datatype').val();
			var address = $('#address').val();
			var data = $('#update').val();
			if(address == '' || data == ''){
				return;
			}
			address = hex2int(address);
			if(datatype == 1){ // 整数型
				ee.processWriteInt({"pid": processId, "address": address, "data": data}, function(ret){
					if(ret.status){
						alert('修改成功');
					}
				});
			} else if(datatype == 2){ // 文本型
				ee.processWriteString({"pid": processId, "address": address, "data": data}, function(ret){
					if(ret.status){
						alert('修改成功');
					}
				});
			} else if(datatype == 3){ // 浮点型
				ee.processWriteFloat({"pid": processId, "address": address, "data": data}, function(ret){
					if(ret.status){
						alert('修改成功');
					}
				});
			} else if(datatype == 4){ // 双浮点型
				ee.processWriteDouble({"pid": processId, "address": address, "data": data}, function(ret){
					if(ret.status){
						alert('修改成功');
					}
				});
			} else if(datatype == 5){ // 字节型
				ee.processWriteBit({"pid": processId, "address": address, "data": data}, function(ret){
					if(ret.status){
						alert('修改成功');
					}
				});
			}
		}

		function renderTable(){
			var trarr = [];
			for(var i = 0; i < mdata.length; i++){
				trarr.push(parseTpl('tr-td.tpl', {
					num: i + 1,
					address: int2hex(mdata[i].address),
					value: mdata[i].value,
					old: mdata[i].old
				}));
			}
			$('#data-body').html(trarr.join(''));
		}

		function parseTpl(id, param){
			var dtrtpl = document.getElementById(id).innerHTML;
            return dtrtpl.replace(/\{[a-zA-Z0-9]+\}/g, function(a, b){
                return param[a.replace(/[\{\}]+/g, "")];
            });
        }

		function loadProcessPath(pid){
			var i = getIndexById(pid);
			if(i == -1){
				return;
			}
			ee.processGetpathId({"pid": pid}, function(ret){
				if(ret.value){
					pdata[i].path = ret.value;
					$('#processPath').val(pdata[i].path);
				} else {
					ee.systemGetSystemDir({}, function(r2){
						if(r2.value){
							if(pid == 0){
								pdata[i].path = r2.value;
							} else if(pid == 4){
								pdata[i].path = r2.value + "/System32";
							} else {
								pdata[i].path = r2.value + "/System32/" + pdata[i].name;
							}
							$('#processPath').val(pdata[i].path);
						}
					});
				}
			});
		}

		function loadProcessList(){
			$('.cover').removeClass('hidden');
			setTimeout(function(){
				ee.processAll({}, function(ret){
					if(ret.list){
						pdata = ret.list;
						$('#processList').html('');
						var arr = ['<option value="">---选择进程---</option>'];
						for(var i = 0; i < pdata.length; i++){
							arr.push('<option value="'+pdata[i].processId+'" '+(processId ==pdata[i].processId?'selected':'')+'>【' + pdata[i].processId + '】' + pdata[i].name + '</option>');
						}
						$('#processList').html(arr.join('\n'));
					}
					$('.cover').addClass('hidden');
				});
			}, 100);			
		}

		function getIndexById(pid){
			for(var i = 0; i < pdata.length; i++){
				if(pdata[i].processId == pid){
					return i;
				}
			}
			return -1;
		}
		
		function int2hex(num){
			return num.toString(16);
		}

		function hex2int(hex){
			return parseInt(hex, 16);
		}
	</script>

	<script id="tr-td.tpl" type="text/html">
		<tr class="trline" id="TR{address}" data-index="{num}">
			<td>{num}</td>
			<td>{address}</td>
			<td class="vv">{value}</td>
			<td class="oo">{old}</td>
		</tr>
	</script>
</body>

</html>